home *** CD-ROM | disk | FTP | other *** search
- /*
- * nr4subr.c: subroutines for net/rom transport layer.
- * Copyright 1989 by Daniel M. Frank, W9NK. Permission granted for
- * non-commercial distribution only.
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <time.h>
- #include <ctype.h>
- #include "global.h"
- #include "mbuf.h"
- #include "timer.h"
- #include "ax25.h"
- #include "netrom.h"
- #include "nr4.h"
- #include "lapb.h"
-
-
- /* Convert a net/rom transport header to host format structure.
- * Return -1 if error, 0 if OK.
- */
-
- int ntohnr4(register struct nr4hdr *hdr, struct mbuf **bpp)
- {
- char axbuf[AXALEN] ;
- char tbuf[NR4MINHDR] ;
-
- if (pullup(bpp, tbuf, NR4MINHDR) < NR4MINHDR)
- return -1 ;
-
- hdr->opcode = tbuf[4] ;
-
- switch (tbuf[4] & NR4OPCODE) {
-
- case NR4OPPID: /* protocol ID extension */
- hdr->u.pid.family = tbuf[0] ;
- hdr->u.pid.proto = tbuf[1] ;
- break ;
-
- case NR4OPCONRQ: /* connect request */
- hdr->u.conreq.myindex = tbuf[0] ;
- hdr->u.conreq.myid = tbuf[1] ;
- if (pullup(bpp,&(hdr->u.conreq.window), 1) < 1)
- return -1 ;
- if (pullup(bpp,axbuf,AXALEN) < AXALEN)
- return -1 ;
- (void)getaxaddr(&hdr->u.conreq.user,axbuf) ;
- if (pullup(bpp,axbuf,AXALEN) < AXALEN)
- return -1 ;
- getaxaddr(&hdr->u.conreq.node,axbuf) ;
- break ;
-
- case NR4OPCONAK: /* connect acknowledge */
- hdr->yourindex = tbuf[0] ;
- hdr->yourid = tbuf[1] ;
- hdr->u.conack.myindex = tbuf[2] ;
- hdr->u.conack.myid = tbuf[3] ;
- if (pullup(bpp,&(hdr->u.conack.window), 1) < 1)
- return -1 ;
- break ;
-
- case NR4OPDISRQ: /* disconnect request */
- hdr->yourindex = tbuf[0] ;
- hdr->yourid = tbuf[1] ;
- break ;
-
- case NR4OPDISAK: /* disconnect acknowledge */
- hdr->yourindex = tbuf[0] ;
- hdr->yourid = tbuf[1] ;
- break ;
-
- case NR4OPINFO: /* information frame */
- hdr->yourindex = tbuf[0] ;
- hdr->yourid = tbuf[1] ;
- hdr->u.info.txseq = tbuf[2] ;
- hdr->u.info.rxseq = tbuf[3] ;
- break ;
-
- case NR4OPACK: /* information acknowledge */
- hdr->yourindex = tbuf[0] ;
- hdr->yourid = tbuf[1] ;
- hdr->u.ack.rxseq = tbuf[3] ;
- break ;
-
- default: /* what kind of frame is this? */
- return -1 ;
- }
-
- return 0 ;
- }
-
-
- struct mbuf *htonnr4(register struct nr4hdr *hdr)
- {
- static unsigned char hlen[NR4NUMOPS] = {5,20,6,5,5,5,5} ;
- struct mbuf *rbuf ;
- register char *cp ;
- unsigned char opcode ;
-
- opcode = hdr->opcode & NR4OPCODE ;
-
- if (opcode >= NR4NUMOPS)
- return NULLBUF ;
-
- if (hdr == (struct nr4hdr *)NULL)
- return NULLBUF ;
-
- if ((rbuf = alloc_mbuf(hlen[opcode])) == NULLBUF)
- return NULLBUF ;
-
- rbuf->cnt = hlen[opcode] ;
- cp = rbuf->data ;
-
- cp[4] = hdr->opcode ;
-
- switch (opcode) {
-
- case NR4OPPID:
- *cp++ = hdr->u.pid.family ;
- *cp = hdr->u.pid.proto ;
- break ;
-
- case NR4OPCONRQ:
- *cp++ = hdr->u.conreq.myindex ;
- *cp++ = hdr->u.conreq.myid ;
- cp += 3 ; /* skip to sixth byte */
- *cp++ = hdr->u.conreq.window ;
- cp = putaxaddr(cp, &hdr->u.conreq.user) ;
- (void) putaxaddr(cp, &hdr->u.conreq.node) ;
- break ;
-
- case NR4OPCONAK:
- *cp++ = hdr->yourindex ;
- *cp++ = hdr->yourid ;
- *cp++ = hdr->u.conack.myindex ;
- *cp++ = hdr->u.conack.myid ;
- cp++ ; /* already loaded pid */
- *cp = hdr->u.conack.window ;
- break ;
-
- case NR4OPDISRQ:
- *cp++ = hdr->yourindex ;
- *cp = hdr->yourid ;
- break ;
-
- case NR4OPDISAK:
- *cp++ = hdr->yourindex ;
- *cp = hdr->yourid ;
- break ;
-
- case NR4OPINFO:
- *cp++ = hdr->yourindex ;
- *cp++ = hdr->yourid ;
- *cp++ = hdr->u.info.txseq ;
- *cp = hdr->u.info.rxseq ;
- break ;
-
- case NR4OPACK:
- *cp++ = hdr->yourindex ;
- *cp++ = hdr->yourid ;
- *++cp = hdr->u.ack.rxseq ; /* skip third byte (tricky yuck) */
- break ;
-
- }
-
- return rbuf ;
- }
-
-
- /* Get a free circuit table entry, and allocate a circuit descriptor.
- * Initialize control block circuit number and ID fields.
- * Return a pointer to the circuit control block if successful,
- * NULLNR4CB if not.
- */
-
- struct nr4cb *new_n4circ(void)
- {
- int i ;
- struct nr4cb *cb ;
-
- for (i = 0 ; i < NR4MAXCIRC ; i++) /* find a free circuit */
- if (Nr4circuits[i].ccb == NULLNR4CB)
- break ;
-
- if (i == NR4MAXCIRC) /* no more circuits */
- return NULLNR4CB ;
-
- if ((cb = Nr4circuits[i].ccb =
- (struct nr4cb *)calloc(1,sizeof(struct nr4cb))) == NULLNR4CB)
- return NULLNR4CB ;
- else {
- cb->mynum = i ;
- cb->myid = Nr4circuits[i].cid ;
- return cb ;
- }
- }
-
-
- /* Set the window size for a circuit and allocate the buffers for
- * the transmit and receive windows. Set the control block window
- * parameter. Return 0 if successful, -1 if not.
- */
-
- int init_nr4window(struct nr4cb *cb, unsigned int window)
- {
-
- if (window == 0 || window > NR4MAXWIN) /* reject silly window sizes */
- return -1 ;
-
- if ((cb->txbufs =
- (struct nr4txbuf *)calloc(window,sizeof(struct nr4txbuf)))
- == (struct nr4txbuf *)0)
- return -1 ;
-
- if ((cb->rxbufs =
- (struct nr4rxbuf *)calloc(window,sizeof(struct nr4rxbuf)))
- == (struct nr4rxbuf *)0) {
- free(cb->txbufs) ;
- cb->txbufs = (struct nr4txbuf *)0 ;
- return -1 ;
- }
-
- cb->window = window ;
-
- return 0 ;
- }
-
-
- /* Free a circuit. Deallocate the control block and buffers, and
- * increment the circuit ID. No return value.
- */
-
- void free_n4circ(struct nr4cb *cb)
- {
- unsigned circ ;
-
- if (cb == NULLNR4CB)
- return ;
-
- circ = cb->mynum ;
-
- if (cb->txbufs != (struct nr4txbuf *)0)
- free(cb->txbufs) ;
-
- if (cb->rxbufs != (struct nr4rxbuf *)0)
- free(cb->rxbufs) ;
-
- /* Better be safe than sorry: */
-
- free_q(&cb->txq) ;
- free_q(&cb->rxq) ;
-
- free(cb) ;
-
- if (circ > NR4MAXCIRC) /* Shouldn't happen. */
- return ;
-
- Nr4circuits[circ].ccb = NULLNR4CB ;
-
- Nr4circuits[circ].cid++ ;
- }
-
- /* See if any open circuit matches the given parameters. This is used
- * to prevent opening multiple circuits on a duplicate connect request.
- * Returns the control block address if a match is found, or NULLNR4CB
- * otherwise.
- */
-
- struct nr4cb *match_n4circ(int index, int id, struct ax25_addr *user,
- struct ax25_addr *node)
- {
- int i ;
- struct nr4cb *cb ;
-
- for (i = 0 ; i < NR4MAXCIRC ; i++) {
- if ((cb = Nr4circuits[i].ccb) == NULLNR4CB)
- continue ; /* not an open circuit */
- if (cb->yournum == index && cb->yourid == id
- && addreq(&cb->user,user) && addreq(&cb->node,node))
- return cb ;
- }
-
- /* if we get to here, we didn't find a match */
-
- return NULLNR4CB ;
- }
-
- /* Validate the index and id of a local circuit, returning the control
- * block if it is valid, or NULLNR4CB if it is not.
- */
-
- struct nr4cb *get_n4circ(int index, int id)
- {
- struct nr4cb *cb ;
-
- if (index >= NR4MAXCIRC)
- return NULLNR4CB ;
-
- if ((cb = Nr4circuits[index].ccb) == NULLNR4CB)
- return NULLNR4CB ;
-
- if (cb->myid == id)
- return cb ;
- else
- return NULLNR4CB ;
- }
-
- /* Return 1 if b is "between" (modulo the size of an unsigned char)
- * a and c, 0 otherwise.
- */
-
- int nr4between(unsigned a, unsigned b, unsigned c)
- {
- if ((a <= b && b < c) || (c < a && a <= b) || (b < c && c < a))
- return 1 ;
- else
- return 0 ;
- }
-
- /* Set up default timer values, etc., in newly connected control block.
- */
-
- void nr4defaults(struct nr4cb *cb)
- {
- int i ;
- struct timer *t ;
-
- if (cb == NULLNR4CB)
- return ;
-
- /* Set up the ACK and CHOKE timers */
-
- cb->tack.start = Nr4acktime / MSPTICK ;
- cb->tack.func = nr4ackit ;
- cb->tack.arg = (char *)cb ;
-
- cb->tchoke.start = Nr4choketime / MSPTICK ;
- cb->tchoke.func = nr4unchoke ;
- cb->tchoke.arg = (char *)cb ;
-
- cb->rxpastwin = cb->window ;
-
- /* Don't actually set the timers, since this is done */
- /* in nr4sbuf */
-
- for (i = 0 ; i < cb->window ; i++) {
- t = &cb->txbufs[i].tretry ;
- t->func = nr4txtimeout ;
- t->arg = (char *)cb ;
- }
- }
-
- /* See if this control block address is valid */
-
- int nr4valcb(struct nr4cb *cb)
- {
- int i ;
-
- if (cb == NULLNR4CB)
- return 0 ;
-
- for (i = 0 ; i < NR4MAXCIRC ; i++)
- if (Nr4circuits[i].ccb == cb)
- return 1 ;
-
- return 0 ;
- }
-